#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/fs.h>

// GPIO5寄存器地址定义
#define GPIO5_DR  		(0x020AC000)  // 数据寄存器
#define GPIO5_DRIR  	(0x020AC004)  // 方向寄存器,0为输入，1为输出
#define GPIO5_PSR  		(0x020AC008)  // 状态寄存器
#define GPIO5_ICR1  	(0x020AC00C)  // 中断配制寄存器1
#define GPIO5_ICR2  	(0x020AC010)  // 中断配制寄存器2
#define GPIO5_ICRIMR    (0x020AC014)  // 中断掩码寄存器
#define GPIO5_ICRISR    (0x020AC018)  // 中断状态寄存器
#define GPIO5_EDGE_SEL  (0x020AC01C)  // 边缘选择寄存器，用以配制双边沿触发中断
#define GPIO5_1_MASK  (1 << 1)  // GPIO5_1掩码(SNVS_TAMPER1)
// GPIO5_1引脚复用控制寄存器
#define IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1  (0x2290000 + 0xC)
// GPIO5_1引脚复用模式为ATL5					
#define ATL5  (5)
#define GPIO5_1_MUX_MODE  ATL5
#define GPIO5_1_MUX_MODE_MASK (0xF)
// GPIO5_1引脚控制寄存器，配制电气属性，如上下拉等
#define IOMUXC_SNVS_SW_PAD_CTL_PAD_SNVS_TAMPER1  (0x2290000 + 0x50)
// GPIO5时钟控制寄存器
#define CCM_CCGR1  (0x20C4000 + 0x6C)
#define GPIO5_CLK_MASK  (3 << 30)
// imx平台gpio转化为整数打宏定义，在gpio_to_irq用到
#define IMX_GPIO_NR(bank, nr)	(((bank) - 1) * 32 + (nr))

// 添加__iomem标记，编译器会检查此地址，确保在io空间
struct key_ctl_pin
{
	unsigned int __iomem* dr_pin;
	unsigned int __iomem* drir_pin;
	unsigned int __iomem* edge_sel_pin;
	unsigned int __iomem* mux_pin;
	unsigned int __iomem* ctl_pin;
	unsigned int __iomem* clk_pin;
};

// 设备结构体
struct my_key_dev {
	struct cdev cdev;           // 字符设备结构体
    struct key_ctl_pin pin;     // key 寄存器映射
	dev_t devno;                // 设备号
	struct class* my_key_class;
	struct device* my_key_device;
    struct mutex mutex;         // 用于同步的互斥体
	volatile unsigned int key_push_cnt;  // 按键按下的次数
	struct timer_list timer;    // 定时器
	wait_queue_head_t wq;       // 等待队列头
	struct fasync_struct* fasync; // 异步通知结构体
	unsigned int irq;           // 虚拟中断号
	volatile int ev_press;      // 按键按下标志
	volatile char key_val;      // 按键值
};